
#ifndef _HTTP_COMM_HTTP_CURL_CLIENT_CUSTORM_H_
#define _HTTP_COMM_HTTP_CURL_CLIENT_CUSTORM_H_

#include "intf_http_client.h"

struct curl_slist;

namespace comm
{
namespace http
{
namespace custorm
{
class CHttpRequest;
class CHttpResponse;
class CCUrlHttpClient : public IHttpClient
{ 
  private:
    class CUnitOfWork
    {
      public:
        CUnitOfWork(CCUrlHttpClient& rHttpClient);
        ~CUnitOfWork(void);

      public:
        void RegisterDirtyHeader(
            struct curl_slist* pHeaderList);

        void RegisterDirtySSLOption(void);
        void RegisterDirtyRedirectOption(void);

        void CleanUp(void);

      private:
        bool ShouldCleanUpHeader(void) const;
        void CleanUpHeader(void);
        bool ShouldCleanUpSSLOption(void) const;
        void CleanUpSSLOption(void);
        bool ShouldCleanUpRedirectOption(void) const;
        void CleanUpRedirectOption(void);

      private:
        CCUrlHttpClient& m_rHttpClient;
        struct curl_slist* m_pHeaderList;
        bool m_bSSLOptionDirty;
        bool m_bRedirectOptionDirty;
    };

  public:
    CCUrlHttpClient(void);
    virtual ~CCUrlHttpClient(void);

  public:
    virtual uint32_t Init(void);

    virtual uint32_t Get(
        const CHttpRequest& rRequest, CHttpResponse& rResponse);

    virtual uint32_t Post(
        const CHttpRequest& rRequest, const std::string& strPostData, CHttpResponse& rResponse);

    virtual void SetProxy(
        const std::string& sProxyHost, uint16_t wProxyPort);
    virtual const std::string& GetProxy(void) const;

    virtual const std::string& GetLastError(void) const;

  private:
    bool WasInitialized(void);
    bool InitCUrlHandler(void);
    bool CreateCUrlHandler(void);
    void DisableSignal(void);
    void SetupCallback(void);
    void SetupUserAgent(void);

    void SetupGetOption(void);
    void SetupGetData(const CHttpRequest& rRequest);
    void SetupUrl(const std::string& sUrl);

    void SetupCommonOption(
        const CHttpRequest& rRequest,
        CHttpResponse& rResponse,
        CUnitOfWork& rUnitOfWork);
    void SetupTimeout(const CHttpRequest& rRequest);
    void SetupDataReceiver(CHttpResponse& rResponse);
    void SetupHeaders(const CHttpRequest& rRequest, CUnitOfWork& rUnitOfWork);
    struct curl_slist* AssembleHeaderList(const CHttpRequest& rRequest);
    void ResetHeaders(void);
    void SetupSSLOption(const CHttpRequest& rRequest, CUnitOfWork& rUnitOfWork);
    void ResetSSLOption(void);
    void SetupRedirectOption(
        const CHttpRequest& rRequest, CUnitOfWork& rUnitOfWork);
    void ResetRedirectOption(void);

    uint32_t Perform(void);

    void SetupPostOption(void);
    void SetupPostData(const std::string& strPostData);
    void SetupProxy(const std::string& sProxy);
    void AssembleProxy(const std::string& sProxyHost, uint16_t wProxyPort);

    static size_t ProcessResponseBody(
        void* pData, size_t nBlockSize, size_t nBlock, void* pReceiver);

    static size_t ProcessResponseHeader(
        void* pData, size_t nBlockSize, size_t nBlock, void* pReceiver);

  private:
    void* m_pCUrlHandler;
    std::string m_sErrMsg;
    std::string m_sProxy;
};

}
}
}

#endif // _HTTP_COMM_HTTP_CURL_CLIENT_CUSTORM_H_
